package game.editer.core;

import game.data.FrameData;
import game.data.ActionData;
import game.data.ProjectRoleData;
import hx.assets.XmlFuture;
import haxe.io.Bytes;
import js.node.util.TextEncoder;
import haxe.Exception;
import hx.assets.XmlAtlas;
import game.utils.XmlTools;
import sys.io.File;
import game.data.ProjectDataExport;
import game.utils.FileSystem;
import game.assets.Hxwz2RolePackageFuture;

using haxe.io.Path;
using StringTools;

class ExportABProject {
	/**
	 * 转换旧版本xml格式代码
	 * @param path 
	 * @param cb 
	 */
	public static function exportByXml(path:String, cb:String->String->Void):Void {
		// 先检查png文件是否存在
		var pngPath = path.replace("xml", "png");
		if (!sys.FileSystem.exists(pngPath)) {
			cb("PNG文件不存在", null);
			return;
		}
		var projectName = path.withoutDirectory().withoutExtension();
		var exportDir = Path.join([path.directory(), "Export", projectName]);
		var imageDir = Path.join([exportDir, "images"]);
		var soundsDir = Path.join([exportDir, "sound"]);
		FileSystem.createDirectory(exportDir);
		FileSystem.createDirectory(imageDir);
		FileSystem.createDirectory(soundsDir);
		new XmlFuture(path, true).onComplete((xml) -> {
			var roleData = new ProjectRoleData();
			roleData.offestConfig = {
				content: {
					x: Std.parseFloat(xml.firstElement().get("px")),
					y: Std.parseFloat(xml.firstElement().get("py")),
				}
			}
			roleData.atlas.push("content");
			var textureNames:Map<String, Bool> = [];
			var textures:Array<Xml> = [];
			for (action in xml.firstElement().elements()) {
				var actionData = new ActionData();
				actionData.fps = 18;
				actionData.name = action.get("name");
				roleData.actions.set(actionData.name, actionData);
				for (subTexture in action.elements()) {
					var frameData = new FrameData();
					frameData.name = "content:" + subTexture.get("name");
					actionData.addFrame(frameData);
					if (!textureNames.exists(subTexture.get("name"))) {
						textureNames.set(subTexture.get("name"), true);
						textures.push(subTexture);
					}
				}
			}
			var textureAtlas = Xml.createDocument();
			var root = Xml.createElement("TextureAtlas");
			textureAtlas.addChild(root);
			for (item in textures) {
				root.addChild(item);
			}
			textureAtlas = XmlTools.removeDuplicateNodes(textureAtlas);
			File.saveContent(Path.join([imageDir, "content.xml"]), textureAtlas.toString());
			File.saveBytes(Path.join([imageDir, "content.png"]), File.getBytes(pngPath));
			var export = new ProjectDataExport(roleData);
			File.saveContent(Path.join([exportDir, projectName + ".abproj"]), export.export());
			cb(null, exportDir);
		}).onError(err -> {
			cb("无法加载xml文件" + path, null);
		});
	}

	/**
	 * 转换旧版本data格式代码
	 * @param path 
	 * @param cb 
	 */
	public static function export(path:String, cb:String->String->Void):Void {
		var future = new Hxwz2RolePackageFuture(path, true);
		future.onComplete((roleData) -> {
			trace("加载完成");
			try {
				// var exportDir = Path.join([path.filePaths[0], "Export"]);
				var projectName = path.withoutDirectory().withoutExtension();
				var exportDir = Path.join([path.directory(), "Export", projectName]);
				var imageDir = Path.join([exportDir, "images"]);
				var soundsDir = Path.join([exportDir, "sound"]);
				FileSystem.createDirectory(exportDir);
				FileSystem.createDirectory(imageDir);
				FileSystem.createDirectory(soundsDir);
				// 将项目储存到Export目录下
				// 删除不存在的sound音频
				for (data in roleData.data.actions) {
					for (frame in data.frames) {
						if (frame.sound != null && roleData.getSound(frame.sound) == null) {
							frame.sound = null;
						}
					}
				}
				var p = new ProjectDataExport(roleData.data);
				var data = p.export();
				File.saveContent(Path.join([exportDir, projectName + ".abproj"]), data);
				// 将资源储存
				var xmlPaths = [];
				for (e in future.zip.entrys) {
					var name = e.fileName.withoutExtension();
					var saveName = name.withoutDirectory();
					if (e.fileName == "content.png") {
						// 储存角色精灵图
						File.saveBytes(Path.join([imageDir, saveName + ".png"]), future.decode(e.data));
						var xml = @:privateAccess cast(roleData.getAtlas("content"), XmlAtlas).__xml;
						xml = XmlTools.removeDuplicateNodes(xml);
						File.saveContent(Path.join([imageDir, saveName + ".xml"]), xml.toString());
					} else if (StringTools.endsWith(e.fileName, "png")) {
						// 图片精灵图
						if (future.zip.entrys.exists(saveName + ".xml")) {
							File.saveBytes(Path.join([imageDir, saveName + ".png"]), future.decode(e.data));
							// 这里需要检查是否为UTF16字符，如果是则需要换行
							var xmlData = future.decode(future.zip.entrys.get(saveName + ".xml").data);
							var xmlPath = Path.join([imageDir, saveName + ".xml"]);
							File.saveBytes(xmlPath, xmlData);
							xmlPaths.push(xmlPath);
						}
					} else if (StringTools.endsWith(e.fileName, "mp3")) {
						// 音频资源
						File.saveBytes(Path.join([soundsDir, saveName + ".mp3"]), future.decode(e.data));
					}
				}
				var maxCounts = xmlPaths.length;
				// 需要重新加载一遍xml，然后重新储存，确保xml数据为UTF-8编码
				function load() {
					var path = xmlPaths.shift();
					if (path == null) {
						if (maxCounts == 0)
							cb(null, exportDir);
						return;
					}
					var future = new XmlFuture(path, true);
					future.onComplete((xml) -> {
						File.saveContent(path, xml.toString());
						maxCounts--;
						load();
					}).onError(err -> {
						cb("xml parser error:" + path, null);
					});
				}
				for (i in 0...10) {
					load();
				}
			} catch (e:Exception) {
				cb(e.message, null);
			}
		});
		future.onError((e) -> {
			// 错误处理
			trace("加载失败", e.errorCode, e.error);
			cb("项目资源无法正常被解析", null);
		});
		future.post();
	}

	/**
	 * 将UTF-16转换为UTF-8
	 * @param xmlData 
	 * @return Bytes
	 */
	public static function utf16toUtf8(xmlData:Bytes):Bytes {
		// try {
		// 	var xml:Xml = Xml.parse(xmlData.toString());
		// 	return Bytes.ofString(xml.toString());
		// } catch (e:Exception) {
		try {
			var code:TextEncoder = new TextEncoder();
			var bytes = code.encode(xmlData.toString());
			xmlData = Bytes.ofData(bytes.buffer);
			var xml = Xml.parse(xmlData.toString());
			return Bytes.ofString(xml.toString());
		} catch (e:Exception) {
			trace("Error parsing xml: " + e.message, xmlData.toString());
			return xmlData;
		}
		// }
	}
}
